"""
市场分析器

提供市场趋势分析、市场状态识别、技术指标计算等功能。
"""

import asyncio
import logging
import math
from datetime import datetime, timedelta
from decimal import Decimal
from enum import Enum
from typing import Dict, List, Optional, Tuple, Any
from dataclasses import dataclass, field


class MarketTrend(Enum):
    """市场趋势"""
    STRONG_UPTREND = "strong_uptrend"       # 强上升趋势
    UPTREND = "uptrend"                     # 上升趋势
    SIDEWAYS = "sideways"                   # 横盘整理
    DOWNTREND = "downtrend"                 # 下降趋势
    STRONG_DOWNTREND = "strong_downtrend"   # 强下降趋势


class MarketRegime(Enum):
    """市场状态"""
    BULL_MARKET = "bull_market"             # 牛市
    BEAR_MARKET = "bear_market"             # 熊市
    VOLATILE_MARKET = "volatile_market"     # 震荡市
    TRENDING_MARKET = "trending_market"     # 趋势市
    RANGE_BOUND = "range_bound"             # 区间震荡


@dataclass
class TechnicalIndicators:
    """技术指标"""
    # 趋势指标
    sma_20: Optional[float] = None          # 20日简单移动平均
    sma_50: Optional[float] = None          # 50日简单移动平均
    ema_12: Optional[float] = None          # 12日指数移动平均
    ema_26: Optional[float] = None          # 26日指数移动平均
    macd: Optional[float] = None            # MACD
    macd_signal: Optional[float] = None     # MACD信号线
    
    # 动量指标
    rsi: Optional[float] = None             # RSI相对强弱指数
    stoch_k: Optional[float] = None         # 随机指标K值
    stoch_d: Optional[float] = None         # 随机指标D值
    
    # 波动率指标
    bollinger_upper: Optional[float] = None # 布林带上轨
    bollinger_middle: Optional[float] = None # 布林带中轨
    bollinger_lower: Optional[float] = None # 布林带下轨
    atr: Optional[float] = None             # 平均真实波幅
    
    # 成交量指标
    volume_sma: Optional[float] = None      # 成交量移动平均
    obv: Optional[float] = None             # 能量潮指标
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'sma_20': self.sma_20,
            'sma_50': self.sma_50,
            'ema_12': self.ema_12,
            'ema_26': self.ema_26,
            'macd': self.macd,
            'macd_signal': self.macd_signal,
            'rsi': self.rsi,
            'stoch_k': self.stoch_k,
            'stoch_d': self.stoch_d,
            'bollinger_upper': self.bollinger_upper,
            'bollinger_middle': self.bollinger_middle,
            'bollinger_lower': self.bollinger_lower,
            'atr': self.atr,
            'volume_sma': self.volume_sma,
            'obv': self.obv
        }


@dataclass
class AnalysisResult:
    """分析结果"""
    symbol: str
    timestamp: datetime
    trend: MarketTrend
    regime: MarketRegime
    confidence: float  # 0.0 - 1.0
    indicators: TechnicalIndicators
    support_levels: List[float] = field(default_factory=list)
    resistance_levels: List[float] = field(default_factory=list)
    analysis_summary: str = ""
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            'symbol': self.symbol,
            'timestamp': self.timestamp.isoformat(),
            'trend': self.trend.value,
            'regime': self.regime.value,
            'confidence': self.confidence,
            'indicators': self.indicators.to_dict(),
            'support_levels': self.support_levels,
            'resistance_levels': self.resistance_levels,
            'analysis_summary': self.analysis_summary
        }


@dataclass
class MarketData:
    """市场数据点"""
    timestamp: datetime
    open_price: float
    high: float
    low: float
    close: float
    volume: int
    
    def typical_price(self) -> float:
        """典型价格"""
        return (self.high + self.low + self.close) / 3
    
    def true_range(self, prev_close: Optional[float] = None) -> float:
        """真实波幅"""
        if prev_close is None:
            return self.high - self.low
        
        return max(
            self.high - self.low,
            abs(self.high - prev_close),
            abs(self.low - prev_close)
        )


class MarketAnalyzer:
    """市场分析器"""
    
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        
        # 数据存储
        self.market_data: Dict[str, List[MarketData]] = {}
        self.analysis_cache: Dict[str, AnalysisResult] = {}
        
        # 分析配置
        self.max_data_points = 500  # 最大数据点数
        self._lock = asyncio.Lock()
    
    async def add_market_data(self, symbol: str, data: MarketData):
        """添加市场数据"""
        async with self._lock:
            if symbol not in self.market_data:
                self.market_data[symbol] = []
            
            self.market_data[symbol].append(data)
            
            # 限制数据长度
            if len(self.market_data[symbol]) > self.max_data_points:
                self.market_data[symbol] = self.market_data[symbol][-self.max_data_points:]
    
    async def analyze_market(self, symbol: str) -> Optional[AnalysisResult]:
        """分析市场"""
        if symbol not in self.market_data or len(self.market_data[symbol]) < 50:
            return None
        
        data = self.market_data[symbol]
        
        # 计算技术指标
        indicators = await self._calculate_indicators(data)
        
        # 识别趋势
        trend = await self._identify_trend(data, indicators)
        
        # 识别市场状态
        regime = await self._identify_regime(data, indicators)
        
        # 计算支撑阻力位
        support_levels, resistance_levels = await self._calculate_support_resistance(data)
        
        # 计算置信度
        confidence = await self._calculate_confidence(data, indicators, trend, regime)
        
        # 生成分析摘要
        summary = await self._generate_summary(symbol, trend, regime, indicators)
        
        result = AnalysisResult(
            symbol=symbol,
            timestamp=data[-1].timestamp,
            trend=trend,
            regime=regime,
            confidence=confidence,
            indicators=indicators,
            support_levels=support_levels,
            resistance_levels=resistance_levels,
            analysis_summary=summary
        )
        
        # 缓存结果
        async with self._lock:
            self.analysis_cache[symbol] = result
        
        return result
    
    async def _calculate_indicators(self, data: List[MarketData]) -> TechnicalIndicators:
        """计算技术指标"""
        indicators = TechnicalIndicators()
        
        if len(data) < 50:
            return indicators
        
        closes = [d.close for d in data]
        highs = [d.high for d in data]
        lows = [d.low for d in data]
        volumes = [d.volume for d in data]
        
        # 移动平均线
        if len(closes) >= 20:
            indicators.sma_20 = sum(closes[-20:]) / 20
        
        if len(closes) >= 50:
            indicators.sma_50 = sum(closes[-50:]) / 50
        
        # 指数移动平均
        indicators.ema_12 = self._calculate_ema(closes, 12)
        indicators.ema_26 = self._calculate_ema(closes, 26)
        
        # MACD
        if indicators.ema_12 and indicators.ema_26:
            indicators.macd = indicators.ema_12 - indicators.ema_26
            # 简化的MACD信号线计算
            if len(closes) >= 35:
                macd_values = []
                for i in range(26, len(closes)):
                    ema12 = self._calculate_ema(closes[:i+1], 12)
                    ema26 = self._calculate_ema(closes[:i+1], 26)
                    if ema12 and ema26:
                        macd_values.append(ema12 - ema26)
                
                if len(macd_values) >= 9:
                    indicators.macd_signal = self._calculate_ema(macd_values, 9)
        
        # RSI
        indicators.rsi = self._calculate_rsi(closes)
        
        # 随机指标
        indicators.stoch_k, indicators.stoch_d = self._calculate_stochastic(highs, lows, closes)
        
        # 布林带
        if indicators.sma_20:
            std_dev = math.sqrt(sum((c - indicators.sma_20) ** 2 for c in closes[-20:]) / 20)
            indicators.bollinger_upper = indicators.sma_20 + 2 * std_dev
            indicators.bollinger_middle = indicators.sma_20
            indicators.bollinger_lower = indicators.sma_20 - 2 * std_dev
        
        # ATR
        indicators.atr = self._calculate_atr(data)
        
        # 成交量指标
        if len(volumes) >= 20:
            indicators.volume_sma = sum(volumes[-20:]) / 20
        
        indicators.obv = self._calculate_obv(data)
        
        return indicators
    
    def _calculate_ema(self, values: List[float], period: int) -> Optional[float]:
        """计算指数移动平均"""
        if len(values) < period:
            return None
        
        multiplier = 2 / (period + 1)
        ema = sum(values[:period]) / period  # 初始SMA
        
        for i in range(period, len(values)):
            ema = (values[i] * multiplier) + (ema * (1 - multiplier))
        
        return ema
    
    def _calculate_rsi(self, closes: List[float], period: int = 14) -> Optional[float]:
        """计算RSI"""
        if len(closes) < period + 1:
            return None
        
        gains = []
        losses = []
        
        for i in range(1, len(closes)):
            change = closes[i] - closes[i-1]
            if change > 0:
                gains.append(change)
                losses.append(0)
            else:
                gains.append(0)
                losses.append(abs(change))
        
        if len(gains) < period:
            return None
        
        avg_gain = sum(gains[-period:]) / period
        avg_loss = sum(losses[-period:]) / period
        
        if avg_loss == 0:
            return 100
        
        rs = avg_gain / avg_loss
        rsi = 100 - (100 / (1 + rs))
        
        return rsi
    
    def _calculate_stochastic(self, highs: List[float], lows: List[float], 
                            closes: List[float], k_period: int = 14, 
                            d_period: int = 3) -> Tuple[Optional[float], Optional[float]]:
        """计算随机指标"""
        if len(closes) < k_period:
            return None, None
        
        # 计算%K
        recent_highs = highs[-k_period:]
        recent_lows = lows[-k_period:]
        current_close = closes[-1]
        
        highest_high = max(recent_highs)
        lowest_low = min(recent_lows)
        
        if highest_high == lowest_low:
            k_value = 50
        else:
            k_value = ((current_close - lowest_low) / (highest_high - lowest_low)) * 100
        
        # 简化的%D计算（这里只返回当前%K值）
        d_value = k_value  # 实际应该是%K的移动平均
        
        return k_value, d_value
    
    def _calculate_atr(self, data: List[MarketData], period: int = 14) -> Optional[float]:
        """计算平均真实波幅"""
        if len(data) < period + 1:
            return None
        
        true_ranges = []
        for i in range(1, len(data)):
            tr = data[i].true_range(data[i-1].close)
            true_ranges.append(tr)
        
        if len(true_ranges) < period:
            return None
        
        return sum(true_ranges[-period:]) / period
    
    def _calculate_obv(self, data: List[MarketData]) -> Optional[float]:
        """计算能量潮指标"""
        if len(data) < 2:
            return None
        
        obv = 0
        for i in range(1, len(data)):
            if data[i].close > data[i-1].close:
                obv += data[i].volume
            elif data[i].close < data[i-1].close:
                obv -= data[i].volume
        
        return obv
    
    async def _identify_trend(self, data: List[MarketData], 
                            indicators: TechnicalIndicators) -> MarketTrend:
        """识别趋势"""
        closes = [d.close for d in data]
        
        # 基于移动平均线的趋势判断
        trend_score = 0
        
        # 价格与移动平均线关系
        current_price = closes[-1]
        if indicators.sma_20 and current_price > indicators.sma_20:
            trend_score += 1
        elif indicators.sma_20 and current_price < indicators.sma_20:
            trend_score -= 1
        
        if indicators.sma_50 and current_price > indicators.sma_50:
            trend_score += 1
        elif indicators.sma_50 and current_price < indicators.sma_50:
            trend_score -= 1
        
        # 移动平均线排列
        if (indicators.sma_20 and indicators.sma_50 and 
            indicators.sma_20 > indicators.sma_50):
            trend_score += 1
        elif (indicators.sma_20 and indicators.sma_50 and 
              indicators.sma_20 < indicators.sma_50):
            trend_score -= 1
        
        # MACD趋势
        if indicators.macd and indicators.macd > 0:
            trend_score += 1
        elif indicators.macd and indicators.macd < 0:
            trend_score -= 1
        
        # 价格动量
        if len(closes) >= 20:
            price_change = (closes[-1] - closes[-20]) / closes[-20]
            if price_change > 0.05:  # 5%以上涨幅
                trend_score += 2
            elif price_change < -0.05:  # 5%以上跌幅
                trend_score -= 2
        
        # 根据得分判断趋势
        if trend_score >= 4:
            return MarketTrend.STRONG_UPTREND
        elif trend_score >= 2:
            return MarketTrend.UPTREND
        elif trend_score <= -4:
            return MarketTrend.STRONG_DOWNTREND
        elif trend_score <= -2:
            return MarketTrend.DOWNTREND
        else:
            return MarketTrend.SIDEWAYS
    
    async def _identify_regime(self, data: List[MarketData], 
                             indicators: TechnicalIndicators) -> MarketRegime:
        """识别市场状态"""
        closes = [d.close for d in data]
        
        if len(closes) < 50:
            return MarketRegime.RANGE_BOUND
        
        # 计算波动率
        returns = [(closes[i] - closes[i-1]) / closes[i-1] for i in range(1, len(closes))]
        volatility = math.sqrt(sum(r ** 2 for r in returns[-20:]) / 20) if len(returns) >= 20 else 0
        
        # 计算趋势强度
        if indicators.sma_20 and indicators.sma_50:
            trend_strength = abs(indicators.sma_20 - indicators.sma_50) / indicators.sma_50
        else:
            trend_strength = 0
        
        # 价格变化
        price_change = (closes[-1] - closes[-50]) / closes[-50]
        
        # 判断市场状态
        if volatility > 0.03:  # 高波动
            return MarketRegime.VOLATILE_MARKET
        elif trend_strength > 0.05:  # 强趋势
            return MarketRegime.TRENDING_MARKET
        elif price_change > 0.2:  # 大幅上涨
            return MarketRegime.BULL_MARKET
        elif price_change < -0.2:  # 大幅下跌
            return MarketRegime.BEAR_MARKET
        else:
            return MarketRegime.RANGE_BOUND
    
    async def _calculate_support_resistance(self, data: List[MarketData]) -> Tuple[List[float], List[float]]:
        """计算支撑阻力位"""
        if len(data) < 20:
            return [], []
        
        highs = [d.high for d in data[-50:]]  # 最近50个数据点
        lows = [d.low for d in data[-50:]]
        
        # 简单的支撑阻力位计算
        # 找到局部高点和低点
        resistance_levels = []
        support_levels = []
        
        # 寻找局部极值
        for i in range(2, len(highs) - 2):
            # 局部高点
            if (highs[i] > highs[i-1] and highs[i] > highs[i-2] and 
                highs[i] > highs[i+1] and highs[i] > highs[i+2]):
                resistance_levels.append(highs[i])
            
            # 局部低点
            if (lows[i] < lows[i-1] and lows[i] < lows[i-2] and 
                lows[i] < lows[i+1] and lows[i] < lows[i+2]):
                support_levels.append(lows[i])
        
        # 去重并排序
        resistance_levels = sorted(list(set(resistance_levels)), reverse=True)[:3]
        support_levels = sorted(list(set(support_levels)))[:3]
        
        return support_levels, resistance_levels
    
    async def _calculate_confidence(self, data: List[MarketData], 
                                  indicators: TechnicalIndicators,
                                  trend: MarketTrend, 
                                  regime: MarketRegime) -> float:
        """计算分析置信度"""
        confidence = 0.5  # 基础置信度
        
        # 数据量充足性
        if len(data) >= 100:
            confidence += 0.1
        elif len(data) >= 50:
            confidence += 0.05
        
        # 指标一致性
        indicator_count = 0
        consistent_indicators = 0
        
        # 检查趋势指标一致性
        if indicators.sma_20 and indicators.sma_50:
            indicator_count += 1
            if ((trend in [MarketTrend.UPTREND, MarketTrend.STRONG_UPTREND] and 
                 indicators.sma_20 > indicators.sma_50) or
                (trend in [MarketTrend.DOWNTREND, MarketTrend.STRONG_DOWNTREND] and 
                 indicators.sma_20 < indicators.sma_50)):
                consistent_indicators += 1
        
        if indicators.macd is not None:
            indicator_count += 1
            if ((trend in [MarketTrend.UPTREND, MarketTrend.STRONG_UPTREND] and 
                 indicators.macd > 0) or
                (trend in [MarketTrend.DOWNTREND, MarketTrend.STRONG_DOWNTREND] and 
                 indicators.macd < 0)):
                consistent_indicators += 1
        
        if indicators.rsi is not None:
            indicator_count += 1
            if ((trend in [MarketTrend.UPTREND, MarketTrend.STRONG_UPTREND] and 
                 indicators.rsi > 50) or
                (trend in [MarketTrend.DOWNTREND, MarketTrend.STRONG_DOWNTREND] and 
                 indicators.rsi < 50)):
                consistent_indicators += 1
        
        # 根据指标一致性调整置信度
        if indicator_count > 0:
            consistency_ratio = consistent_indicators / indicator_count
            confidence += consistency_ratio * 0.3
        
        # 趋势强度调整
        if trend in [MarketTrend.STRONG_UPTREND, MarketTrend.STRONG_DOWNTREND]:
            confidence += 0.1
        
        return min(0.95, max(0.1, confidence))
    
    async def _generate_summary(self, symbol: str, trend: MarketTrend, 
                              regime: MarketRegime, 
                              indicators: TechnicalIndicators) -> str:
        """生成分析摘要"""
        summary_parts = []
        
        # 趋势描述
        trend_desc = {
            MarketTrend.STRONG_UPTREND: "强劲上升趋势",
            MarketTrend.UPTREND: "上升趋势",
            MarketTrend.SIDEWAYS: "横盘整理",
            MarketTrend.DOWNTREND: "下降趋势",
            MarketTrend.STRONG_DOWNTREND: "强劲下降趋势"
        }
        summary_parts.append(f"{symbol} 当前处于{trend_desc[trend]}")
        
        # 市场状态描述
        regime_desc = {
            MarketRegime.BULL_MARKET: "牛市环境",
            MarketRegime.BEAR_MARKET: "熊市环境",
            MarketRegime.VOLATILE_MARKET: "高波动环境",
            MarketRegime.TRENDING_MARKET: "趋势性行情",
            MarketRegime.RANGE_BOUND: "区间震荡"
        }
        summary_parts.append(f"市场状态为{regime_desc[regime]}")
        
        # 技术指标描述
        if indicators.rsi is not None:
            if indicators.rsi > 70:
                summary_parts.append("RSI显示超买状态")
            elif indicators.rsi < 30:
                summary_parts.append("RSI显示超卖状态")
            else:
                summary_parts.append("RSI处于正常区间")
        
        if indicators.macd is not None and indicators.macd_signal is not None:
            if indicators.macd > indicators.macd_signal:
                summary_parts.append("MACD呈现多头排列")
            else:
                summary_parts.append("MACD呈现空头排列")
        
        return "；".join(summary_parts) + "。"
    
    async def get_latest_analysis(self, symbol: str) -> Optional[AnalysisResult]:
        """获取最新分析结果"""
        async with self._lock:
            return self.analysis_cache.get(symbol)
    
    async def get_all_analyses(self) -> Dict[str, AnalysisResult]:
        """获取所有分析结果"""
        async with self._lock:
            return self.analysis_cache.copy()
    
    async def clear_data(self, symbol: Optional[str] = None):
        """清理数据"""
        async with self._lock:
            if symbol:
                self.market_data.pop(symbol, None)
                self.analysis_cache.pop(symbol, None)
                self.logger.info(f"清理 {symbol} 的分析数据")
            else:
                self.market_data.clear()
                self.analysis_cache.clear()
                self.logger.info("清理所有分析数据")
    
    async def get_statistics(self) -> Dict[str, Any]:
        """获取分析统计"""
        async with self._lock:
            stats = {
                'analyzed_symbols': len(self.analysis_cache),
                'data_symbols': len(self.market_data),
                'total_data_points': sum(len(data) for data in self.market_data.values()),
                'trend_distribution': {},
                'regime_distribution': {}
            }
            
            # 统计趋势分布
            for result in self.analysis_cache.values():
                trend = result.trend.value
                stats['trend_distribution'][trend] = stats['trend_distribution'].get(trend, 0) + 1
                
                regime = result.regime.value
                stats['regime_distribution'][regime] = stats['regime_distribution'].get(regime, 0) + 1
            
            return stats